package com.cls.business.controller;

import com.cls.business.entity.*;
import com.cls.business.service.*;
import com.cls.business.service.impl.ClassifyTopicService;
import com.cls.business.service.impl.ExportExcelService;
import com.cls.business.vo.SelectEntrustVO;
import com.cls.business.vo.SummaryDeclareTopic;
import com.cls.common.annotation.ControllerEndpoint;
import com.cls.common.controller.BaseController;
import com.cls.common.entity.MyConstant;
import com.cls.common.entity.QueryRequest;
import com.cls.common.entity.ResponseVO;
import com.cls.common.enums.DictEnum;
import com.cls.common.utils.FileUtil;
import com.cls.common.utils.MyUtil;
import com.cls.system.entity.SysDict;
import com.cls.system.entity.SysFile;
import com.cls.system.entity.Template;
import com.cls.system.service.ISysDictService;
import com.cls.system.service.ISysFileService;
import com.cls.system.service.ITemplateService;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 年度周期管理 Controller
 *
 * @author wmm
 * @date 2020-11-11 10:45:55
 */
@Slf4j
@Validated
@Controller
@RequiredArgsConstructor
public class LifecycleController extends BaseController {

    private final ITopicPlanService topicPlanService;

    private final IDeclareTopicService declareTopicService;

    private final IDeclarePlanService declarePlanService;

    private final ITopicService topicService;

    private final IEntrustTopicService entrustTopicService;

    private final ClassifyTopicService classifyTopicService;

    private final ISysDictService sysDictService;

    private final IMemberInfoService memberInfoService;

    private final IApplicantInfoService applicantInfoService;

    private final IDeclareEntrustService declareEntrustService;

    private final ITemplateService templateService;

    private final ISysFileService sysFileService;

    /**
    * 课题计划表列表页面
    **/
    @GetMapping(MyConstant.VIEW_PREFIX + "biz/lifecycle/{type}")
    public String lifecycleIndex(Model model, @PathVariable("type") String topicClassifyCode){
        model.addAttribute("topicClassifyCode", topicClassifyCode);
        if(DictEnum.ENTRUST.getCode().equals(topicClassifyCode)){
            List<SysDict> planNos = sysDictService.findByParentCode(DictEnum.PLAN_NO.getCode());
            model.addAttribute("planNos", planNos);
            return MyUtil.view("business/lifecycle/listEntrust");
        }
        return MyUtil.view("business/lifecycle/listAnnual");
    }


    @GetMapping("biz/lifecycle/{topicClassifyCode}/list")
    @ResponseBody
    @RequiresPermissions("lifecycle:list")
    public ResponseVO topicPlanList(QueryRequest request, TopicPlan topicPlan, @PathVariable("topicClassifyCode") String topicClassifyCode) {
        if(StringUtils.isEmpty(topicClassifyCode)){
            ResponseVO.failure("参数异常！");
        }

        // year + planNo 转期次
        if(DictEnum.ENTRUST.getCode().equals(topicClassifyCode)) {
            if (StringUtils.isNotBlank(topicPlan.getPlanNo())) {
                String period = topicPlan.getYear() + "-" + topicPlan.getPlanNo();
                topicPlan.setPeriod(period);
            }
        } else {
            topicPlan.setPeriod(topicPlan.getYear());
        }
        topicPlan.setYear(null);
        topicPlan.setPlanNo(null);
        topicPlan.setTopicClassifyCode(topicClassifyCode);
        PageInfo<TopicPlan> pageInfo =  topicPlanService.findTopicPlans(request, topicPlan);
        return ResponseVO.success(pageInfo);
    }



    @ControllerEndpoint(operation = "结束资格审查", exceptionMessage = "结束评审失败")
    @PostMapping("lifecyclePlan/{planId}/check")
    @ResponseBody
    public ResponseVO checkTopicPlan(@PathVariable Long planId) {
        // 变更前，计划的状态为PLAN_CREATE
        TopicPlan beforeTopicPlan = topicPlanService.getById(planId);
        if(beforeTopicPlan == null){
            throw new IllegalArgumentException("参数错误！");
        }
        String beforeStatusCode =  beforeTopicPlan.getStatusCode();
        if(!DictEnum.PLAN_CREATE.getCode().equals(beforeStatusCode)){
            return ResponseVO.failure("期次状态不正确！");
        }

        // 变更前，所有申报课题的状态可能为为NO_APPLY、PRE_APPLY、CHECK_FAILED、CHECK_PASSED
        List<String> status = new ArrayList();
        status.add(DictEnum.NO_APPLY.getCode());
        status.add(DictEnum.PRE_APPLY.getCode());
        status.add(DictEnum.CHECK_FAILED.getCode());
        status.add(DictEnum.CHECK_PASSED.getCode());
        if(!checkStatusCodeForTopicPlan(beforeTopicPlan, status)){
            return ResponseVO.failure("申报课题资格审查未完成！");
        }

        // 设置操作成功后，计划的状态
        beforeTopicPlan.setStatusCode(DictEnum.PLAN_CHECK.getCode());
        classifyTopicService.classifyTopic(beforeTopicPlan);
        return ResponseVO.success("该期计划资格审查完成！");
    }

    @ControllerEndpoint(operation = "结束学科分类", exceptionMessage = "结束学科分类失败")
    @PostMapping("lifecyclePlan/{planId}/subject")
    @ResponseBody
    public ResponseVO subjectTopicPlan(@PathVariable Long planId, @RequestBody String topicClassifyCode) {
        // 变更前，计划的状态为PLAN_CHECK|PLAN_ASSIGN
        TopicPlan beforeTopicPlan = topicPlanService.getById(planId);
        if(beforeTopicPlan == null){
            throw new IllegalArgumentException("参数错误！");
        }
        String beforeStatusCode =  beforeTopicPlan.getStatusCode();
        if(DictEnum.ANNUAL.getCode().equals(topicClassifyCode) && !DictEnum.PLAN_CHECK.getCode().equals(beforeStatusCode)){
            return ResponseVO.failure("期次状态不正确！");
        }
        if(DictEnum.ENTRUST.getCode().equals(topicClassifyCode) && !DictEnum.PLAN_ASSIGN.getCode().equals(beforeStatusCode)){
            return ResponseVO.failure("期次状态不正确！");
        }

        Topic param = new Topic();
        param.setPlanId(planId);
        boolean isAllCheck = true;
        if(DictEnum.ANNUAL.getCode().equals(topicClassifyCode)){
            List<Topic> topics = topicService.findTopicsByPlanId(planId);
            for(Topic one: topics ){
                if(!DictEnum.PLAN_SUBJECT.getCode().equals(one.getStatusTypeCode())){
                    isAllCheck = false;
                    break;
                }
            }
        }
        else if(DictEnum.ENTRUST.getCode().equals(topicClassifyCode)) {
            List<EntrustTopic> entrustTopics = entrustTopicService.findEntrustTopicsByPlanId(planId);
            for(EntrustTopic one: entrustTopics ){
                if(!DictEnum.PLAN_SUBJECT.getCode().equals(one.getStatusTypeCode())){
                    isAllCheck = false;
                    break;
                }
            }
        }
        if(!isAllCheck){
            return ResponseVO.failure("所有的选题未完成学科分类！");
        }
        List<String> status = new ArrayList();
        status.add(DictEnum.NO_APPLY.getCode());
        status.add(DictEnum.PRE_APPLY.getCode());
        status.add(DictEnum.CHECK_FAILED.getCode());
        status.add(DictEnum.CHECK_PASSED.getCode());
        status.add(DictEnum.CONCLUDE_ASSIGN.getCode());
        String tip;
        if(checkStatusCodeForTopicPlan(beforeTopicPlan, status)){
            beforeTopicPlan.setStatusCode(DictEnum.PLAN_SUBJECT.getCode());
            boolean succeed = false;
            if(DictEnum.ANNUAL.getCode().equals(topicClassifyCode)){
                succeed = topicPlanService.endClassifyTopic(beforeTopicPlan);
            }else if(DictEnum.ENTRUST.getCode().equals(topicClassifyCode)){
                succeed = topicPlanService.endClassifyEntrustTopic(beforeTopicPlan);
            }
            if(succeed){
                tip = "结束学科分类成功！";
            } else {
                tip = "请稍后再试！自动专家分配正在运行中...";
            }
        } else {
            tip = "申请课题状态不正确！";
        }
        return ResponseVO.success(tip);
    }


    @ControllerEndpoint(operation = "结束评审", exceptionMessage = "结束评审失败")
    @PostMapping("lifecyclePlan/{planId}/review")
    @ResponseBody
//    @RequiresPermissions("topicPlan:review")
    public ResponseVO reviewTopicPlan(@PathVariable Long planId) {
        // 变更前，计划的状态为PLAN_EXPERT
        TopicPlan beforeTopicPlan = topicPlanService.getById(planId);
        if(beforeTopicPlan == null){
            throw new IllegalArgumentException("参数错误！");
        }
        String beforeStatusCode =  beforeTopicPlan.getStatusCode();
        if(!DictEnum.PLAN_EXPERT.getCode().equals(beforeStatusCode)){
            return ResponseVO.failure("期次状态不正确！");
        }
        List<String> status = new ArrayList();
        status.add(DictEnum.NO_APPLY.getCode());
        status.add(DictEnum.PRE_APPLY.getCode());
        status.add(DictEnum.CHECK_FAILED.getCode());
        status.add(DictEnum.CHECK_PASSED_REVIEW.getCode());
        if(checkStatusCodeForTopicPlan(beforeTopicPlan, status)){
            beforeTopicPlan.setStatusCode(DictEnum.PLAN_REVIEW.getCode());
            topicPlanService.updateTopicPlanStatusCode(beforeTopicPlan);
        } else {
            return ResponseVO.failure("申报课题的状态不一致，可能还存在未评审的课题！");
        }
        return ResponseVO.success("结束评审成功！");
    }

    @ControllerEndpoint(operation = "结束专家分配", exceptionMessage = "结束评审失败")
    @PostMapping("lifecyclePlan/{planId}/expert")
    @ResponseBody
//    @RequiresPermissions("topicPlan:check")
    public ResponseVO expertTopicPlan(@PathVariable Long planId) {
        // 变更前，计划的状态为PLAN_SUBJECT
        TopicPlan beforeTopicPlan = topicPlanService.getById(planId);
        if(beforeTopicPlan == null){
            throw new IllegalArgumentException("参数错误！");
        }
        String beforeStatusCode =  beforeTopicPlan.getStatusCode();
        if(!DictEnum.PLAN_SUBJECT.getCode().equals(beforeStatusCode)){
            return ResponseVO.failure("期次状态不正确！");
        }

        Topic param = new Topic();
        param.setPlanId(planId);
        boolean isAllCheck = true;
        if(DictEnum.ANNUAL.getCode().equals(beforeTopicPlan.getTopicClassifyCode())){
            List<Topic> topics = topicService.findTopicsByPlanId(planId);
            for(Topic one: topics ){
                if(!DictEnum.PLAN_EXPERT.getCode().equals(one.getStatusTypeCode())){
                    isAllCheck = false;
                    break;
                }
            }
        } else if(DictEnum.ENTRUST.getCode().equals(beforeTopicPlan.getTopicClassifyCode())) {
            List<EntrustTopic> entrustTopics = entrustTopicService.findEntrustTopicsByPlanId(planId);
            for(EntrustTopic one: entrustTopics ){
                if(!DictEnum.PLAN_EXPERT.getCode().equals(one.getStatusTypeCode())){
                    isAllCheck = false;
                    break;
                }
            }
        }
        if(!isAllCheck){
            return ResponseVO.failure("所有的选题未完成专家分配！");
        }

        List<String> status = new ArrayList();
        status.add(DictEnum.NO_APPLY.getCode());
        status.add(DictEnum.PRE_APPLY.getCode());
        status.add(DictEnum.CHECK_FAILED.getCode());
        status.add(DictEnum.CHECK_PASSED.getCode());
        status.add(DictEnum.CONCLUDE_ASSIGN.getCode());
        if(checkStatusCodeForTopicPlan(beforeTopicPlan, status)){
            beforeTopicPlan.setStatusCode(DictEnum.PLAN_EXPERT.getCode());
            topicPlanService.updateTopicPlanStatusCode(beforeTopicPlan);
            topicPlanService.sendReviewEmail(beforeTopicPlan);
        } else {
            return ResponseVO.failure("申请课题状态不正确！");
        }

        return ResponseVO.success("操作成功！");
    }

    private boolean checkStatusCodeForTopicPlan(TopicPlan topicPlan, List<String> declareStatus){
        // 是否所有的申请已经都资格审查完成
        DeclarePlan param = new DeclarePlan();
        param.setPlanId(topicPlan.getPlanId());
        List<DeclarePlan> declarePlans = declarePlanService.findDeclarePlans(param);
        boolean isAllChecked = true;
        for(DeclarePlan declarePlan:declarePlans) {
            DeclareTopic declareTopic = declareTopicService.getById(declarePlan.getDeclareId());
            String statusTypeCode = declareTopic.getStatusTypeCode();
            if(!declareStatus.contains(statusTypeCode)){
                isAllChecked = false;
                break;
            }
        }
        return isAllChecked;
    }


    /**
     * 选择委托课题列表页面
     **/
    @GetMapping(MyConstant.VIEW_PREFIX + "biz/lifecyclePlan/{planId}/chooseEntrusts")
    public String entrustListIndex(Model model, @PathVariable("planId") String planId){
        model.addAttribute("planId", planId);
        return MyUtil.view("business/lifecycle/chooseEntrusts");
    }

    /**
     * 被选委托课题列表页面
     **/
    @GetMapping(MyConstant.VIEW_PREFIX + "biz/lifecyclePlan/{planId}/entrusts")
    public String chooseEntrustIndex(Model model, @PathVariable("planId") String planId){
        model.addAttribute("planId", planId);
        return MyUtil.view("business/lifecycle/entrusts");
    }


    /**
     * 查看委托课题列表
     **/
    @GetMapping(MyConstant.VIEW_PREFIX + "biz/lifecyclePlan/{planId}/showEntrusts")
    public String showEntrustsListIndex(Model model, @PathVariable("planId") String planId){
        model.addAttribute("planId", planId);
        return MyUtil.view("business/lifecycle/showEntrusts");
    }



//    /**
//     * 分派委托课题
//     **/
//    @ControllerEndpoint(operation = "分派委托课题", exceptionMessage = "分派委托课题失败")
//    @PostMapping("lifecyclePlan/{planId}/assignEntrusts")
//    @ResponseBody
//    public ResponseVO assignEntrusts(@PathVariable Long planId, @RequestBody List<SelectEntrustVO> entrusts) {
//        if (planId == null || entrusts == null) {
//            return ResponseVO.failure("参数错误！");
//        }
//
//        TopicPlan plan = topicPlanService.getById(planId);
//        if(plan == null ){
//            return ResponseVO.success("指定计划不存在！");
//        }
//        if(!DictEnum.PLAN_CREATE.getCode().equals(plan.getStatusCode())){
//            return ResponseVO.success("已完成");
//        }
//        topicPlanService.assignEntrusts(planId, entrusts);
//        return ResponseVO.success("操作成功！");
//    }

    /**
     * 分派委托课题
     **/
    @ControllerEndpoint(operation = "分派委托课题", exceptionMessage = "分派委托课题失败")
    @PostMapping("lifecyclePlan/{planId}/assignEntrusts/{declarePlanId}")
    @ResponseBody
    public ResponseVO assignEntrusts(@PathVariable Long planId, @PathVariable Long declarePlanId) {
        if (planId == null || declarePlanId == null) {
            return ResponseVO.failure("参数错误！");
        }

        TopicPlan plan = topicPlanService.getById(planId);
        if(plan == null ){
            return ResponseVO.success("指定计划不存在！");
        }
        if(!DictEnum.PLAN_CREATE.getCode().equals(plan.getStatusCode())){
            return ResponseVO.success("已完成");
        }
        topicPlanService.assignEntrust(planId, declarePlanId);
        return ResponseVO.success("操作成功！");
    }

    /**
     * 分派委托课题
     **/
    @ControllerEndpoint(operation = "分派委托课题", exceptionMessage = "分派委托课题失败")
    @PostMapping("lifecyclePlan/{planId}/unAssignEntrusts/{declarePlanId}")
    @ResponseBody
    public ResponseVO unAssignEntrusts(@PathVariable Long planId, @PathVariable Long declarePlanId) {
        if (planId == null || declarePlanId == null) {
            return ResponseVO.failure("参数错误！");
        }

        TopicPlan plan = topicPlanService.getById(planId);
        if(plan == null ){
            return ResponseVO.success("指定计划不存在！");
        }
        if(!DictEnum.PLAN_CREATE.getCode().equals(plan.getStatusCode())){
            return ResponseVO.success("已完成");
        }
        topicPlanService.unAssignEntrusts(declarePlanId);
        return ResponseVO.success("操作成功！");
    }



    @ControllerEndpoint(operation = "结束委托课题分派", exceptionMessage = "结束委托课题分派失败")
    @PostMapping("lifecyclePlan/{planId}/assign")
    @ResponseBody
//    @RequiresPermissions("topicPlan:check")
    public ResponseVO endAssignTopicPlan(@PathVariable Long planId) {
        // 状态变更前的判断
        TopicPlan beforeTopicPlan = topicPlanService.getById(planId);
        if(beforeTopicPlan == null){
            throw new IllegalArgumentException("参数错误！");
        }
        String beforeStatusCode =  beforeTopicPlan.getStatusCode();
        if(!DictEnum.PLAN_CREATE.getCode().equals(beforeStatusCode)){
            return ResponseVO.failure("状态不正确！");
        }
        List<String> status = new ArrayList();
        status.add(DictEnum.CONCLUDE_APPLY.getCode());
        if(checkStatusCodeForTopicPlan(beforeTopicPlan, status)){
            beforeTopicPlan.setStatusCode(DictEnum.PLAN_ASSIGN.getCode());
            topicPlanService.endAssignTopicPlan(beforeTopicPlan);
            classifyTopicService.classifyEntrustTopic(beforeTopicPlan);
            return ResponseVO.success("操作成功！");
        } else{
            return ResponseVO.failure("操作失败！");
        }
    }


    @ControllerEndpoint(operation = "恢复初始化状态", exceptionMessage = "恢复初始化状态失败")
    @PostMapping("lifecyclePlan/{planId}/resume")
    @ResponseBody
    @RequiresPermissions("lifecycle:resume")
    public ResponseVO resumeInitialization(@PathVariable Long planId) {
        // 状态变更前的判断
        TopicPlan beforeTopicPlan = topicPlanService.getById(planId);
        if(beforeTopicPlan == null){
            throw new IllegalArgumentException("参数错误！");
        }
        List<String> status = new ArrayList();
        status.add(DictEnum.PLAN_CHECK.getCode());
        status.add(DictEnum.PLAN_ASSIGN.getCode());
        status.add(DictEnum.PLAN_SUBJECT.getCode());
        status.add(DictEnum.PLAN_EXPERT.getCode());
//        status.add(DictEnum.PLAN_REVIEW.getCode());
        String beforeStatusCode =  beforeTopicPlan.getStatusCode();
        if(DictEnum.PLAN_CREATE.getCode().equals(beforeStatusCode)){
            return ResponseVO.success("已是初始化状态！");
        }
        if(!status.contains(beforeStatusCode)){
            return ResponseVO.failure("专家评审已结束，不能恢复初始化状态！");
        }
        topicPlanService.resumeInitialization(beforeTopicPlan);
        return ResponseVO.success("操作成功！");
    }

    @ControllerEndpoint(operation = "导出委托课题统计表", exceptionMessage = "导出委托课题统计表失败")
    @GetMapping("biz/lifecycle/{topicClassifyCode}/exportEntrustTopic")
    @RequiresPermissions("lifecycle:list")
    public void exportEntrustTopic(TopicPlan topicPlan, @PathVariable("topicClassifyCode") String topicClassifyCode, HttpServletResponse response) {
        // year + planNo 转期次
        String period = "";
        if(DictEnum.ENTRUST.getCode().equals(topicClassifyCode)) {
            if (StringUtils.isNotBlank(topicPlan.getPlanNo())) {
                period = topicPlan.getYear() + "-" + topicPlan.getPlanNo();
            }
        } else {
            period = topicPlan.getYear();
        }
        TopicPlan existPlan = topicPlanService.selectByPeriod(period);
        if (existPlan == null) {
            throw new RuntimeException("该期次不存在！");
        }
        Long planId = existPlan.getPlanId();

        List<DeclareTopic> declareTopics = declareTopicService.selectByPlanId(planId);
        if (declareTopics == null || declareTopics.size() < 1) {
            throw new RuntimeException("无数据！");
        }

        List<SummaryDeclareTopic> summaries = new ArrayList<>();
        for(DeclareTopic one:declareTopics){
            ApplicantInfo applicantInfo = applicantInfoService.getById(one.getApplicantId());
            MemberInfo param = new MemberInfo();
            param.setDeclareId(one.getDeclareId());

            List<MemberInfo> memberInfos = memberInfoService.findMemberInfos(param);

            SummaryDeclareTopic summary = new SummaryDeclareTopic(sysDictService, one, applicantInfo, memberInfos);
            DeclareEntrust entrust = declareEntrustService.findByDeclareId(one.getDeclareId());
            if(entrust != null){
                MemberInfo initiator = memberInfoService.getById(entrust.getInitiatorId());
                if(initiator != null){
                    summary.setInitiator(initiator.getName());
                }
                summary.setTopicUnitName(entrust.getTopicUnitName());
            }
            summaries.add(summary);
        }

        Template template = templateService.findByTemplateTypeCode(DictEnum.TEMPLATE_ENTRUST_TOPIC.getCode());
        if (template == null) {
            throw new RuntimeException("模板文件不存在！");
        }
        SysFile sysFile = sysFileService.getById(template.getFileId());
        if (sysFile == null) {
            throw new RuntimeException("模板文件不存在！");
        }

        try {
            FileUtil.downloadExcel(ExportExcelService.exportEntrustTopic(summaries, period, sysFile.getUrl()), response, URLEncoder.encode("filename11", "UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
